/*****************************************************************************/
/*                        >>> func_socket.c <<<                              */
/*	Trabajo Practico 2do. cuatrimestre 2011                                  */
/*	TP:"FUSELAJE"                                                            */
/*	GRUPO: Reduce Fat Fast                                                   */
/*	INTEGRANTES: Emanuel Genovese                                            */
/*               Federico Gabriel Garcia                                     */
/*               Federico Pioli                                              */
/*               Esther Insfrain                                             */
/*               Luciano Bagattin                                            */
/*	Fecha UM:                                                                */
/*****************************************************************************/

/*****************************************************************************/
/*		        	Include					                                 */
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include "func_socket.h"
#include <sys/un.h>
#include <unistd.h>
#include "constants_commons.h"
#include "func_strings.h"
#include "log.h"

/******************************************************************************/
/* Nombre de Procedimiento: fConectar                                         */
/* Parametros: no recibe parametros                                           */
/*                                                                            */
/*	                                                                          */
/* Descripcion: Conectar a un proceso                                         */
/******************************************************************************/

int fConectar(int iPuerto, char * sIp, char * sFileLog, char * process,
		t_log *log) {
	struct sockaddr_in server;
	int iCentral;

	if ((iCentral = (int) socket(AF_INET, SOCK_STREAM, 0)) == -1) { // obtener socket a la escucha
		log_error(log, process, "Message error: %s",
				"Error al crear el socket");
		return -1;
	}
	log_info(log, process, "Message info: %s", "Exito al crear el socket");
	server.sin_family = AF_INET;
	server.sin_port = htons(iPuerto);
	server.sin_addr.s_addr = inet_addr(sIp);
	bzero(&(server.sin_zero), 8);

	if (connect(iCentral, (struct sockaddr*) &server, sizeof(struct sockaddr))
			== -1) {

		log_error(log, process, "Message error: %s",
				"La conexion no se establecio ");

		return -1;
	}
	log_info(log, process, "Message error: %s",
			"La conexion se establecio con exito");

	return iCentral;

}

/******************************************************************************/
/* Nombre de Procedimiento: fPrepararSocket                                   */
/* Parametros: no recibe parametros                                           */
/*                                                                            */
/*	                                                                          */
/* Descripcion: Funcion que se encarga de preparar el socket tanto para       */
/*              cuando es cliente o cuando es servidor.                       */
/******************************************************************************/

int fPrepararSocket(
		char* sPuerto_local_para_el_socket /*NULL para que el puerto sea random*/,
		char* sIP_local, char* sFuncion_Socket, int reutilizar, char * sFileLog,
		char * process, t_log *log) {
	/*Declaracion de variables locales*/

	int iYes = 1;
	int iSocket = -1; /*descriptor que estoy abriendo*/
	int iPuerto;
	/*fin de la declaracion de variables locales*/

	struct sockaddr_in addr_server;

	/*is reutilizar es 1 entonces preparo el socket para que lo tome como cliente y si es 0 es un server.Configuro para un server.*/

	log_info(log, process, "Message info: %s", process);

	pCadaInt(sPuerto_local_para_el_socket, &iPuerto);

	/* Inicializamos el socket*/

	log_info(log, process, "Message error: %s", "tamos dentro");

	/* Creo el socket */
	iSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (iSocket == -1) {
		printf("ME FALLO EL SOCKET");
		log_error(log, process, "Message error: %s",
				"Error al setear el socket");

		return -1;
	}
	log_info(log, process, "Message info: %s",
			"Se seteo el socket correctamente");
	if (setsockopt(iSocket, SOL_SOCKET, SO_REUSEADDR, (char*) &iYes,
			sizeof(int)) == -1) {
		printf("setear las opciones de sockets");
		log_error(log, process, "Message error: %s",
				"Error al setear las opciones de  socket");

		return -1;
	}
	log_info(log, process, "Message info: %s",
			"Se seteo las opciones del socket correctamente");
	if ((strcmp(sPuerto_local_para_el_socket, "NULL")) != 0) {
		//Ordenacion de maquina AF_INET
		addr_server.sin_family = AF_INET;
		//Ordeno la IP, le asigno la que trae en el header de la funcion
		addr_server.sin_addr.s_addr = inet_addr(sIP_local);
		//Ordeno el puerto a la ordenacion de la red
		addr_server.sin_port = htons(iPuerto); //K-htons(iPuerto);

		//Completo con 0 el resto de la estructura
		memset(addr_server.sin_zero, 0, 8);

		/*Asocio el socket de escucha a la direccion */
		if (bind(iSocket, (struct sockaddr *) &addr_server,
				sizeof(struct sockaddr)) == -1) {

			log_error(log, process, "Message error: %s", "Error en el bind");

			return -1; // Retornamos 1 dado que la funcion fallo
		} //fin del if(bind

	} //fin del if(strcmp

	return iSocket;

} //fin del fPrepararSocket

/******************************************************************************/
/* Nombre de Procedimiento: fEscuchar                                         */
/* Parametros:                                                                */
/*            iSocket: socket por el cual va a escuchar                       */
/*            iCantConexiones: es la cantidad  de conexiones maximas que      */
/*          	  va a soportar                                               */
/*	                                                                          */
/* Descripcion: Funcion que se encarga de preparar el socket tanto para       */
/*              cuando es cliente o cuando es servidor.                       */
/******************************************************************************/
int fEscuchar(int iSocket, int iCantConecciones, char * sFileLog,
		char * process, t_log *log) {

	if (listen(iSocket, iCantConecciones) == -1) {
		log_error(log, process, "Message error: %s", "Error en el listen");
		return 0;

	}
	log_info(log, process, "Message info: %s", "Exito  en el listen");

	return 1;
} //fin del fEscuchar

/******************************************************************************/
/* Nombre de Procedimiento: fCerrarSocket                                     */
/* Parametros: int iSocket:Socket al cual cerraremos                          */
/*                                                                            */
/*	                                                                          */
/* Descripcion: Funcion que me cierra un socket                               */
/******************************************************************************/

int fCerrar(int iDescriptor_del_socket, char * sFileLog, char * process,
		t_log *log) {

	char sDescriptor_del_socket[5 + 11]="\0";

sprintf	(sDescriptor_del_socket,"%i cerrado",iDescriptor_del_socket);

	log_info(log, process, "Message info: %s", sDescriptor_del_socket);
	return 1;
} //fin fCerrar

/******************************************************************************/
/* Nombre de Procedimiento: fEnviar                                           */
/* Parametros: int iSocket: socket hilo                                       */
/*             respuesta: cadena a enviar                                  */
/*	                                                                          */
/* Descripcion: Funcion que me envia un paquete                               */
/******************************************************************************/

int fEnviar(int iSocket, char *respuesta) {
	/*declaracion de variables locales*/
	char msglog[1024];
	/*fin de la declacaracion de variables locales*/
	memset(msglog, '\0', 1024);
	sprintf(msglog, "%s", respuesta);
	if ((send(iSocket, respuesta, (int) strlen(respuesta), 0)) < 0) {
		sprintf(msglog, "Error al enviar:%s", respuesta);

		return 0;
	} //fin del if
	sprintf(msglog, "Envio:%s", respuesta);

	return 1;

} //fin del fEnviar

/******************************************************************************/
/* Nombre de Funcion: fPrepararSocket_UN                                      */
/* Parametros:                                                                                                                            */
/* Descripcion: Funcion que se encarga de crear el socket                     */
/* Fecha UM:                                                                  */
/******************************************************************************/

int fPrepararSocket_UN(t_log *log, char * process) {
	int iDescriptor; // descriptor de socket

	if ((iDescriptor = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {

		log_error(log, process, "Message error: %s",
				"Error al crear el socket");
		return -1;
	}

	log_info(log, process, "Message info: %s", "Exito al crear el socket");
	return iDescriptor;

} //fin fPrepararSocket_UN

/******************************************************************************/
/* Nombre de Funcion: fConectar_UN                                               */
/* Parametros: iDescriptor_del_socket- socket                                 */
/*                                                                            */
/* Descripcion: Funcion que se encarga de conectar el socket                  */
/* Fecha UM:                                                                  */
/******************************************************************************/
int fConectar_UN(int iDescriptor_del_socket, char *process, t_log *log,
		char * sPath) {
	int len;
	struct sockaddr_un Str_sockaddr_un_paraConnect;
	char sRuta[512] = "\0";

	sprintf(sRuta, "%s%s", sPath, "mysocket");

	Str_sockaddr_un_paraConnect.sun_family = AF_UNIX;
	strcpy(Str_sockaddr_un_paraConnect.sun_path, sRuta);
	len = strlen(Str_sockaddr_un_paraConnect.sun_path)
			+ sizeof(Str_sockaddr_un_paraConnect.sun_family);

	if (connect(iDescriptor_del_socket,
			(struct sockaddr *) &Str_sockaddr_un_paraConnect, len) == -1) {
		log_error(log, process, "Message error: %s",
				"No se ha podido conectar al dispositivo");
		return -1;
	}
	log_info(log, process, "Message info: %s",
			"El dispositivo se conecto correctamente");

	return 0;
} //fin del fConectarUN

/******************************************************************************/
/* Nombre de Funcion: fEscuchaSocketUN                                        */
/* Parametros: iDescriptor_del_socket- socket                                 */
/*                                                                            */
/* Descripcion: Funcion que preparar al socket para la escucha                */
/* Fecha UM:                                                                  */
/******************************************************************************/
int fEscuchaSocketUN(int iDescriptor_del_socket, char * sNombreProceso,
		t_log *log, char *sPath) {
	struct sockaddr_un socket_un_struct;
	int len;
	char sRuta[512] = "\0";

	sprintf(sRuta, "%s%s", sPath, "mysocket");
	socket_un_struct.sun_family = AF_UNIX;
	strcpy(socket_un_struct.sun_path, sRuta);

	unlink(socket_un_struct.sun_path);
	len = strlen(socket_un_struct.sun_path)
			+ sizeof(socket_un_struct.sun_family);
	if (bind(iDescriptor_del_socket, (struct sockaddr *) &socket_un_struct, len)
			== -1) {
		// fEscribirLog(3,sNombreProceso,"Error al hacer el bind para conectar con el shell!");
		log_error(log, sNombreProceso, "Message error: %s",
				"Error al hacer el bind para conectar con el shell!");
		return 1;
	} //fin del if
	log_error(log, sNombreProceso, "Message info: %s",
			"Exito al hacer el bind para conectar con la consola!");

	if (listen(iDescriptor_del_socket, 1) == -1) {
		log_error(log, sNombreProceso, "Message error: %s",
				"Error al hacer el listen para conectar con el shell!");
		return 1;
	} //fin del if
	log_error(log, sNombreProceso, "Message info: %s",
			"Exito  al hacer el listen para conectar con la consola!");
	return 0;
} //fin fEscuchaSocketUN

